package com.code2roc.xhood.asm;

import com.code2roc.xhood.model.ObscureConfig;
import com.code2roc.xhood.model.ObsureEnum;
import com.code2roc.xhood.util.ObscureUtil;
import org.apache.commons.lang3.StringUtils;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;

import java.util.*;

public class PackageDefineVisitor extends ClassVisitor {
    private String packageName;
    private String className;
    private String classPackageName;
    private List<String> interfaceList;
    private LinkedHashMap<String, String> modifyMap;
    private List<String> obscureIgnorePackages;
    private boolean modify = false;
    private String classPath;
    private String packagePath;
    private String outPath;

    public PackageDefineVisitor(ClassVisitor cv, ObscureConfig obscureConfig) {
        super(Opcodes.ASM9, cv);
        interfaceList = new ArrayList<>();
        modifyMap = new LinkedHashMap<>();
        this.packageName = obscureConfig.getPackageName();
        this.obscureIgnorePackages = obscureConfig.getIgnorePackages();
        this.outPath = obscureConfig.getOutPutPath();
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        this.className = name.replace('/', '.');
        List<String> classNameList = new ArrayList<>(Arrays.asList(className.split("\\.")));
        String classSimpleName = classNameList.get(classNameList.size() - 1);
        classNameList.remove(classNameList.size() - 1);
        this.classPackageName = StringUtils.join(classNameList, ".");
        for (String item : interfaces) {
            interfaceList.add(item.replace('/', '.'));
        }
        modify = check();
        if (modify) {
            String obsucrePackagePart = classPackageName.replace(packageName + ".", "");
            List<String> obsucrePackagePartList = new ArrayList<>(Arrays.asList(obsucrePackagePart.split("\\.")));
            for (int i = 0; i < obsucrePackagePartList.size(); i++) {
                String part = obsucrePackagePartList.get(i);
                part = ObscureUtil.getObscureNameV1(part, ObsureEnum.Package);
                obsucrePackagePartList.set(i, part);
            }
            packagePath = packageName.replace(".", "/") + "/" + StringUtils.join(obsucrePackagePartList, "/");
            classPath = packagePath + "/" + classSimpleName;
            String obsucreName = classPath;
            modifyMap.put(name, obsucreName);
            packagePath = outPath + "/" + "classes/" + packagePath;
            classPath = packagePath + "/" + classSimpleName + ".class";
            super.visit(version, access, obsucreName, signature, superName, interfaces);
        } else {
            super.visit(version, access, name, signature, superName, interfaces);
        }

    }

    public LinkedHashMap<String, String> getModifyMap() {
        return modifyMap;
    }

    public boolean isModify() {
        return modify;
    }

    public String getClassPath() {
        return classPath;
    }

    public String getPackagePath() {
        return packagePath;
    }

    private boolean check() {
        boolean modifyInvoke = true;
        boolean exist = false;
        if (classPackageName.equals(packageName)) {
            modifyInvoke = false;
        }
        if(!classPackageName.startsWith(packageName)){
            modifyInvoke = false;
        }
        for (String p : obscureIgnorePackages) {
            if (p.startsWith("*")) {
                if (classPackageName.endsWith(p.replace("*/", ""))) {
                    modifyInvoke = false;
                    break;
                }
            } else {
                if (p.startsWith(classPackageName)) {
                    modifyInvoke = false;
                    break;
                }
            }
        }
        return modifyInvoke;
    }
}
